//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.UIDesigner
{
    using System;
    using System.Collections.Generic;
    using System.Resources;
    using Microsoft.Research.ScientificWorkflow.TridentComposer;
    using Microsoft.Research.ScientificWorkflow.TridentModel;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Media;
    using Microsoft.Research.ScientificWorkflow.TridentUtilities;
    using System.Windows.Input;
    using SR = Microsoft.Research.DataLayer;
    using System.Collections.ObjectModel;
    using System.Collections;
    using System.Workflow.ComponentModel;
    using System.Globalization;
    using System.Collections.Specialized;
    using Microsoft.Research.eResearch.Common.Eventing;
    using System.Linq;
    using System.Text;
    using Microsoft.Research.eResearch.Common.Linq;

    /// <summary>
    /// Helper class for the ComposerControl.
    /// </summary>
    public class ComposerRenderer
    {
        #region Private data
        
        /// <summary>
        /// Drop circle counter.
        /// </summary>
        private static int dropCircleCounter = 1;

        /// <summary>
        /// Selected parameter connections.
        /// </summary>
        private Collection<ParameterConnectionElement> selectedParameterConnections = new Collection<ParameterConnectionElement>();

        /// <summary>
        /// List of datatypes.
        /// </summary>
        private Dictionary<String, DataTypeModel> dataTypes;        

        private Dictionary<string, ActivityParameterDesigner> inputParameterElements = new Dictionary<string, ActivityParameterDesigner>();

        private Dictionary<string, ActivityParameterDesigner> outputParameterElements = new Dictionary<string, ActivityParameterDesigner>();

        /// <summary>
        /// The list of inuse datatypes.
        /// </summary>
        private Dictionary<string, int> inUseDataTypes = new Dictionary<string, int>();

        /// <summary>
        /// Condition data store.
        /// </summary>
        private ConditionDataStore conditionStore;

        /// <summary>
        /// Name of the subsection.
        /// </summary>
        private string subsectionName;

        /// <summary>
        /// Description of the subsection.
        /// </summary>
        private string descSubsection;

        /// <summary>
        /// The application's main window.
        /// </summary>
        private Window mainWindow;

        /// <summary>
        /// The control for which this is the renderer.
        /// </summary>
        private ComposerControl composerControl;

        /// <summary>
        /// The workflowComposer.
        /// </summary>
        private WorkflowComposer wfLoader;

        /// <summary>
        /// This is used to access registry connection.
        /// </summary>
        private SR.Connection registryConnection;

        /// <summary>
        /// Holds the pop up window.
        /// </summary>
        private Window enterNamePopUp;

        /// <summary>
        /// Dictionary of ITridentUiElements.
        /// This is keyed upon Model.UniqueID.
        /// </summary>
        private Dictionary<string, ITridentUIElement> uIElements = new Dictionary<string, ITridentUIElement>();

        /// <summary>
        /// The ui generator.
        /// </summary>
        private TridentUIGenerationVisitor uiGenerationVisitor = new TridentUIGenerationVisitor();

        /// <summary>
        /// The connections visitor.
        /// </summary>
        internal TridentActivityConnectionVisitor connectionVisitor;

        /// <summary>
        /// Instance of parameter binding generation visitor
        /// </summary>
        internal ParameterBindingVisitor parameterBindingVisitor;

        /// <summary>
        /// Collection of currently selected elements.
        /// </summary>
        private SelectedElementsCollection selectedElements;

        #endregion Private data.

        #region Events

        /// <summary>
        /// Fired when the selected activity changes.
        /// </summary>
        public event EventHandler SelectedActivitiesChanged;

        /// <summary>
        /// Fired when the user clicks on the conetxt menu items.
        /// </summary>
        public event EventHandler<ProvenanceModeEventArgs> ProvenanceMenuClick;

        #endregion

        #region Public properties

        /// <summary>
        /// Unique counter for the Ui and the activity name.
        /// </summary>
        public static int UniqueCounter
        {
            get { return ActivityUtilities.UniqueCounter; }
            set { ActivityUtilities.UniqueCounter = value; }
        }

        /// <summary>
        /// Unique counter for the drop circles.
        /// </summary>
        public static int DropCircleCounter
        {
            get { return dropCircleCounter++; }
            set { ComposerRenderer.dropCircleCounter = value; }
        }

        /// <summary>
        /// Gets or stes the SelectedParamConnections.
        /// </summary>
        internal Collection<ParameterConnectionElement> SelectedParamConnections
        {
            get { return selectedParameterConnections; }
        }

        /// <summary>
        /// The datatypes being used by the current workflow.
        /// </summary>
        public Dictionary<string, int> InUseWorkflowDataTypes
        {
            get { return inUseDataTypes; }
        }

        /// <summary>
        /// The complete list of available datatypes.
        /// </summary>
        public Dictionary<String, DataTypeModel> DataTypes
        {
            get { return this.dataTypes; }
        }

        /// <summary>
        /// Get the current workflow model.
        /// </summary>
        public TridentWorkflowModel CurrentWorkflowModel
        {
            get;
            set;
        }

        /// <summary>
        /// 
        /// </summary>
        public Dictionary<string, ActivityParameterDesigner> InputParameterElements 
        {
            get
            {
                return this.inputParameterElements;
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public Dictionary<string, ActivityParameterDesigner> OutputParameterElements
        {
            get
            {
                return this.outputParameterElements;
            }
        }

        /// <summary>
        /// Gets and sets if the workflow is committed.
        /// </summary>
        public bool IsWFCommitted
        {
            get;
            set;
        }

        /// <summary>
        /// Gets the uiElements.
        /// </summary>
        public Dictionary<string, ITridentUIElement> UIElements
        {
            get
            {
                return this.uIElements;
            }
        }

        /// <summary>
        /// Gets the collection of currently selected elements.
        /// </summary>
        public SelectedElementsCollection CurrentSelectedElements
        {
            get
            {
                return this.selectedElements;
            }
        }

        /// <summary>
        /// Gets the composer control.
        /// </summary>
        public ComposerControl CurrentComposerCtrl
        {
            get
            {
                return this.composerControl;
            }
        }

        #endregion

        #region Constructor

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="composerControl">
        /// The control for which this is the renderer.
        /// </param>
        public ComposerRenderer(ComposerControl composerControl,
            SR.Connection regConnection,
            Dictionary<String, DataTypeModel> dataTypes,
            ConditionDataStore conditionDataStore)
        {
            this.mainWindow = Application.Current.MainWindow;
            this.composerControl = composerControl;
            this.registryConnection = regConnection;
            this.wfLoader = this.composerControl.WorkflowComposer;
            this.selectedElements = new SelectedElementsCollection(this);
            this.selectedElements.CollectionChanged += new NotifyCollectionChangedEventHandler(this.OnSelectedItemsCollectionChanged);
            this.dataTypes = dataTypes;
            this.conditionStore = conditionDataStore;
            this.connectionVisitor = new TridentActivityConnectionVisitor(this.composerControl.PositionableElementsCanvas, this.wfLoader, this);
            // this.composerControl.WorkflowspaceGrd.SizeChanged += this.connectionVisitor.GridLayoutUpdated;
            this.composerControl.WorkflowSpaceGrid.SizeChanged += new SizeChangedEventHandler(this.OnWorkspaceSizeChanged);
            parameterBindingVisitor = new ParameterBindingVisitor(this.composerControl.PositionableElementsCanvas, this);
        }

        #endregion Constructor

        #region Public Methods

        /// <summary>
        /// Shows the properties of the currently selected activity or workflow.
        /// </summary>
        public void ShowProperties()
        {
            if (this.selectedElements.Count > 0)
            {
                if (1 == this.selectedElements.Count)
                {
                    if (this.selectedElements[0].Model != null)
                    {
                        this.ShowProperties(this.selectedElements[0].Model);
                    }
                }
                else
                {
                    string name = "Selected Activities";
                    CompositeActivityModel holderModel = new CompositeActivityModel(
                        name,
                        name,
                        name,
                        name,
                        new Collection<ParameterDescriptionModel>(),
                        new Collection<ParameterDescriptionModel>()
                        );

                    holderModel.VisibleOnUI.ActivityVisibility = Visibility.Collapsed;
                    foreach (ITridentUIElement uiElem in this.selectedElements)
                    {
                        if (uiElem.Model != null)
                        {
                            holderModel.Children.Add(uiElem.Model);
                        }
                    }

                    this.ShowProperties(holderModel);
                }
            }
        }

        /// <summary>
        /// Show properties of the activity.
        /// </summary>
        /// <param name="modelToShowPropertiesOf">
        /// Activity.
        /// </param>
        public void ShowProperties(BaseModel modelToShowPropertiesOf)
        {
            if (modelToShowPropertiesOf != null)
            {
                if (modelToShowPropertiesOf.Equals(this.CurrentWorkflowModel.Root))
                {
                    this.UpdatePropPane(modelToShowPropertiesOf, this.CurrentWorkflowModel, false);
                }
                else
                {
                    this.UpdatePropPane(modelToShowPropertiesOf, null, false);
                }
            }
        }

        /// <summary>
        /// Shows the properties.
        /// </summary>
        /// <param name="modelToShowPropertiesOf">The model to show properties of.</param>
        /// <param name="showWorkflowParameters">if set to <c>true</c> shows workflow parameters.</param>
        public void ShowProperties(BaseModel modelToShowPropertiesOf, bool showWorkflowParameters)
        {
            if (modelToShowPropertiesOf != null)
            {
                if (modelToShowPropertiesOf.Equals(this.CurrentWorkflowModel.Root))
                {
                    this.UpdatePropPane(modelToShowPropertiesOf, this.CurrentWorkflowModel, showWorkflowParameters);
                }
                else
                {
                    this.UpdatePropPane(modelToShowPropertiesOf, null, showWorkflowParameters);
                }
            }
        }

        /// <summary>
        /// Add input parameters at runtime. Add only if the property pane is shown to the user.
        /// The input parameters get refreshed anyway when workflow is double clicked.
        /// </summary>
        /// <param name="requiredInpuptParam">The required input parameter to add/remove.</param>
        /// <param name="add">True to add to the list, False otherwise.</param>
        public void UpdateInputParametersInPropertyPane(BaseModel model, ParameterDescriptionModel parameter, bool add)
        {
            Grid grdPropPaneHolder = this.composerControl.grdCentralPane;
            if (grdPropPaneHolder != null)
            {
                PropertiesPane propPane = null;
                if (grdPropPaneHolder.Children.Count > 2 && grdPropPaneHolder.Children[2] is PropertiesPane)
                {
                    propPane = grdPropPaneHolder.Children[2] as PropertiesPane;
                }

                if (null != propPane)
                {
                    parameter.PropertyPaneDisplayName =
                        string.Format(CultureInfo.InvariantCulture, "{0}.{1}", model.Name, parameter.PropertyName);
                    propPane.UpdateInputParameters(parameter, add);
                }
            }
        }

        /// <summary>
        /// This function is used to hide/show all parameter Bindings in current workflow.
        /// </summary>
        /// <param name="changeState">Visibilty of the parameter bindings of the Activity.</param>
        public void ToggleAllParameterBindings(Visibility changeState)
        {
            if (null != this.CurrentWorkflowModel)
            {
                // Make the visibilty of Parameter Connections to collapsed.
                this.ChangeParameterBindingVisibilty(this.CurrentWorkflowModel.Root, changeState);
                //this.RefreshParameterBindingVisibility(this.CurrentWorkflowModel.Root);
                this.parameterBindingVisitor.RefreshVisibility(this.CurrentWorkflowModel.Root);
            }
        }
        
        /// <summary>
        /// Remove the property pane when the workflow changes.
        /// </summary>
        public void RemovePropertyPaneOnChange()
        {
            this.selectedElements.RemoveAllItems();
            this.OnPropPaneClose(this, new EventArgs());
        }

        /// <summary>
        /// Creates the ui representation for the model provided and adds the same to the panel passed.
        /// </summary>
        /// <param name="model">
        /// The model needing to be drawn.
        /// </param>
        /// <param name="addToPanel">
        /// The holder panel.
        /// </param>
        public void UpdateForActivity(BaseModel model, Panel addToPanel)
        {
            #region Arguments check.

            if (null == model)
            {
                throw new ArgumentNullException("model");
            }

            if (null == addToPanel)
            {
                throw new ArgumentNullException("addToPanel");
            }

            #endregion Arguments check.

            ITridentUIElement tridentUiElem = this.uiGenerationVisitor.GenerateUIRepresentation(model, this.dataTypes, this.uIElements, this);
            UIElement uiElem = tridentUiElem as UIElement;
            if (uiElem != null)
            {
                addToPanel.Children.Add(uiElem);
            }
            ICompositeUIElement compositeElement = tridentUiElem as ICompositeUIElement;
            if (compositeElement != null)
            {
                this.connectionVisitor.CreateActivityConnections(compositeElement);
            }
        }
        
        /// <summary>
        /// Initialize the trident element.
        /// </summary>
        /// <param name="tridentUiElem">
        /// The ui representation element.
        /// </param>
        public void InitializeTridentUIElement(ITridentUIElement tridentUIElement)
        {
            if (tridentUIElement != null)
            {
                tridentUIElement.DeleteElement -= this.OnTridentElemDelete;
                tridentUIElement.SelectElement -= this.OnTridentElemSelect;
                tridentUIElement.ShowProperties -= this.OnTridentActivityElemShowProperties;
                tridentUIElement.InsertIntoSubsection -= this.OnInsertIntoSubsection;
                tridentUIElement.ProvenanceMenuClick -= new EventHandler<ProvenanceModeEventArgs>(OnTridentUiElemProvenanceMenuClick);
                tridentUIElement.UpdateClick -= this.OnUpdateClick;

                tridentUIElement.DeleteElement += new EventHandler(this.OnTridentElemDelete);
                tridentUIElement.SelectElement += new EventHandler(this.OnTridentElemSelect);
                tridentUIElement.ShowProperties += new EventHandler(this.OnTridentActivityElemShowProperties);
                tridentUIElement.InsertIntoSubsection += new EventHandler(this.OnInsertIntoSubsection);
                tridentUIElement.UpdateClick += new EventHandler<ModelEventArgs>(this.OnUpdateClick);
                tridentUIElement.ProvenanceMenuClick += new EventHandler<ProvenanceModeEventArgs>(OnTridentUiElemProvenanceMenuClick);

                TridentUIActivityElement tridentActivityElem = tridentUIElement as TridentUIActivityElement;
                if (tridentActivityElem != null)
                {
                    tridentActivityElem.ToggleBindings -= this.OnTridentActivityToggleParamBindings;

                    this.UpdateParamDictionary(tridentActivityElem);
                    tridentActivityElem.ToggleBindings += new EventHandler<ParameterBindingEventArgs>(this.OnTridentActivityToggleParamBindings);
                }

                ISubsectionControl subsectionCtrl = tridentUIElement as ISubsectionControl;
                if (subsectionCtrl != null)
                {
                    subsectionCtrl.RemoveSubsection -= this.OnRemoveSubsection;
                    subsectionCtrl.RemoveSubsection += new EventHandler<RemoveSubsectionEventArgs>(this.OnRemoveSubsection);
                }

                UIElement uiElem = tridentUIElement as UIElement;
                if (uiElem != null)
                {
                    uiElem.PreviewKeyDown -= this.OnTridentElementKeyDown;
                    uiElem.PreviewKeyDown += new KeyEventHandler(this.OnTridentElementKeyDown);
                }
            }
        }

        /// <summary>
        /// This function clears all the UI related stuffs in the Trident Window.
        /// </summary>
        public void ClearUICache()
        {
            // Get the Trident Composer Window.
            Panel mainPanel = this.composerControl.WorkflowSpace;
            mainPanel.Children.Clear();

            foreach (FrameworkElement elem in mainPanel.Children)
            {
                if (elem.Name.Equals("WorkflowRoot"))
                {
                    mainPanel.Children.Remove(elem);
                    break;
                }
            }

            Canvas canvas = this.composerControl.PositionableElementsCanvas;
            canvas.Children.Clear();

            // Clear the data types legend.
            this.ClearDataKeys();
        }

        /// <summary>
        /// Unselects all the ParameterBininds selctions.
        /// </summary>
        public void RemoveParameterSelection()
        {
            if (!(Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl)))
            {
                // Update the style of the previous selected UI elements to "Unselected Style"
                if (this.SelectedParamConnections.Count > 0)
                {
                    foreach (ParameterConnectionElement prevSelected in this.SelectedParamConnections)
                    {
                        // Apply the "Unselected Style".
                        ParameterConnectionElement.ApplyDeselectedStyle(prevSelected);
                    }
                }

                // Clear all the existing the ParameterConnectionElement 
                this.SelectedParamConnections.Clear();
            }

            if (!(Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)))
            {
                this.selectedElements.RemoveAllItems();
            }
        }

        /// <summary>
        /// This function is used to update the Dataypes.
        /// </summary>
        /// <param name="wfModel">Base Model.</param>
        public void UpdateDataTypes(BaseModel workflowModel)
        {
            DataTypesComposer.UpdateDataKeys(workflowModel, this.dataTypes, this.inUseDataTypes);
            this.UpdateDataKey();
        }

        /// <summary>
        /// Clears the in used data types and updates the data type legend.
        /// </summary>
        public void ClearDataKeys()
        {
            this.inUseDataTypes.Clear();
            this.UpdateDataKey();
        }

        public void RefreshUI()
        {
            this.parameterBindingVisitor.RefreshBindings();
        }

        #endregion Public Methods

        #region Private Methods

        private void OnWorkspaceSizeChanged(object sender, SizeChangedEventArgs e)
        {
            this.connectionVisitor.GridLayoutUpdated();
        }

        /// <summary>
        /// Renders the workflow from the Activity Element to UI.
        /// </summary>
        /// <param name="rootActivity">Rooat Activity of thw Workflow.</param>
        internal bool LoadWorkFlow(TridentWorkflowModel wfModel, bool isRefresh)
        {
            Panel mainPanel;
            this.ClearUICache();
            try
            {
                if (wfModel != null)
                {
                    if (wfModel.Root != null)
                    {
                        ComposerRenderer.dropCircleCounter = 1;

                        // Get the Trident Composer Window.
                        mainPanel = this.composerControl.WorkflowSpace;

                        // Set the Name of the Trident Composer to WorkflowRoot. 
                        // This identifies the panel as the WorkFlow Root.
                        mainPanel.Name = "WorkflowRoot";

                        // Clears the previous activity UI Elements.
                        this.uIElements.Clear();

                        // Clears the Condition Data Store
                        if (this.CurrentComposerCtrl.ConditionStore != null)
                        {
                            this.CurrentComposerCtrl.ConditionStore.ClearDataStore();
                        }


                        // Update the Panel with the Activities.
                        this.UpdateForActivity(wfModel.Root, mainPanel);

                      

                        this.CurrentComposerCtrl.UpdateLayout();

                       
                        // Update the binding connections visibilty based on the 
                        // CurrentParameterBinding visibilty of the activity Mdoel.
                        this.parameterBindingVisitor.CreateBindings(wfModel.Root, this.uIElements);

                        this.inUseDataTypes.Clear();

                        this.UpdateDataTypes(wfModel.Root);

                        // Set the current wf model.
                        this.CurrentWorkflowModel = wfModel;
                        if (!isRefresh)
                        {
                            // Find the max value of the activity name in wf.
                            ComposerRenderer.UniqueCounter = SetCounter(wfModel.Root, 0);
                            ComposerRenderer.UniqueCounter++;
                        }
                    }
                }
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleAndThrowBusinessLogicException(
                    exp,
                    TridentErrorConstants.ErrorNumber90000011,
                    exp.Message);
            }

            return true;
        }

        internal void OnTridentElemDelete(object sender, EventArgs e)
        {
            try
            {
                if (this.composerControl.CurrentRenderMode == RenderMode.ComposerMode)
                {
                    MessageBoxResult confirmRes = TridentMessageBox.ShowTridentConfirmationYesNoMessageBox(
                            TridentResourceManager.GetString("ConfirmElemDelete"));

                    if (MessageBoxResult.Yes == confirmRes)
                    {
                        this.DeleteSelectedElements();
                    }
                }
            }
            catch (TridentCustomException exp)
            {
                TridentMessageBox.ShowTridentErrorMessageBox(exp.Message);
            }
            catch (Exception exp)
            {
                TridentErrorHandler.HandleUIException(exp);
                TridentMessageBox.ShowTridentErrorMessageBox(exp.Message);
            }
        }

        private void DeleteSelectedElements()
        {
            foreach (ITridentUIElement uiElem in this.selectedElements)
            {
                if (uiElem.Model.IsCompositeActivityModel)
                {
                    this.DeleteCompositeActivity(uiElem.Model as CompositeActivityModel, uiElem);
                }
                else
                {
                    this.DeleteElement(uiElem.Model, uiElem);
                }
            }

            this.selectedElements.RemoveAllItems();
            this.DeletedIfCondionFromDataStore();
            this.IsWFCommitted = false;
            this.connectionVisitor.DeleteTridentUIElement();
            this.parameterBindingVisitor.RefreshBindings();
            this.OnPropPaneClose(this, new EventArgs());
        }

        /// <summary>
        /// Collects the Garbage Condition connector and remove it from Condition DataStore
        /// </summary>
        private void DeletedIfCondionFromDataStore()
        {
            Collection<ConditionConnector> garbageConnectorList = new Collection<ConditionConnector>();
            if (conditionStore != null)
            {
                Collection<ConditionConnector> connectorList = this.conditionStore.FetchConditionalConnectorList();

                foreach (ConditionConnector connector in connectorList)
                {
                    // Add the Deleted Activities to garbageConnectorList
                    if (!this.CurrentWorkflowModel.ModelsHashtable.Contains(connector.ConditionActivity.UniqueId))
                    {
                        garbageConnectorList.Add(connector);
                    }
                }

                foreach (ConditionConnector connector in garbageConnectorList)
                {
                    this.conditionStore.RemoveFromConditionalConnectorList(connector.ConditionActivity.UniqueId);
                }
            }
        }

        private void DeleteElement(BaseModel deleteModel, ITridentUIElement uiElem)
        {
            if (deleteModel == null)
            {
                return;
            }

            this.parameterBindingVisitor.RemoveParameterBindingsForAll(deleteModel);

            // Get the parent of the child activity
            BaseCompositeModel parentModel = deleteModel.ParentModel;
            if (null != parentModel)
            {
                if (parentModel.Children.Contains(deleteModel) && this.uIElements.ContainsKey(parentModel.UniqueId)
                    && parentModel.Children.Remove(deleteModel))
                {
                    ICompositeUIElement parentUiElem = this.uIElements[parentModel.UniqueId] as ICompositeUIElement;
                    if (parentUiElem != null && parentUiElem.ChildElements.Contains(uiElem))
                    {
                        parentUiElem.RemoveChildElement(uiElem);
                        DataTypesComposer.RemoveDataKeys(uiElem.Model, this.inUseDataTypes);
                        this.UpdateDataKey();

                        // Set the workflow has been updated.
                        if (this.conditionStore != null && deleteModel.IsSimpleActivityModel)
                        {
                            this.conditionStore.RemoveActivityBody(parentModel.UniqueId, deleteModel as SimpleActivityModel);
                            this.conditionStore.RemoveFromConditionalConnectorList(deleteModel.UniqueId);
                        }
                    }
                }
            }
        }

        private void DeleteCompositeActivity(CompositeActivityModel deleteActivityModel, ITridentUIElement uiElem)
        {
            if (null != deleteActivityModel.ParentModel)
            {
                // Remove from condition store.
                if (deleteActivityModel.IsIfElseActivityModel && deleteActivityModel.Children.Count > 1)
                {
                    CompositeActivityModel condition = deleteActivityModel.Children[0] as CompositeActivityModel;
                    if (condition != null && condition.ActivityClass.Equals("TridentBasicActivities.Activities.IfCondition",
                        StringComparison.CurrentCulture))
                    {
                        this.conditionStore.RemoveFromConditionalConnectorList(condition.UniqueId);
                    }
                }

                // Delete the children only.
                if (deleteActivityModel.DeleteBehavior == ActivityDeleteBehavior.DeleteChildren)
                {
                    for (int i = deleteActivityModel.Children.Count - 1; i >= 0; i--)
                    {
                        ITridentUIElement childElem = null;
                        if (this.uIElements.TryGetValue(deleteActivityModel.Children[i].UniqueId, out childElem))
                        {
                            this.DeleteElement(deleteActivityModel.Children[i], childElem);
                        }
                    }

                    deleteActivityModel.Children.Clear();
                }
                // Delete the Activity.
                else if (deleteActivityModel.DeleteBehavior == ActivityDeleteBehavior.DeleteSelf)
                {
                    this.DeleteElement(deleteActivityModel, uiElem);
                }
                // Do not perform a delete.
                else
                {
                    return;
                }
            }
            else
            {
                TridentErrorHandler.ThrowTridentCustomException(
                    TridentErrorConstants.ErrorNumber90000015,
                    "Could not delete the root activity.");
            }
        }

        /// <summary>
        /// Swap the state of the subsection.
        /// </summary>
        /// <param name="sender">
        /// Subsection.
        /// </param>
        internal void SwapSubsectionState(object sender)
        {
            TridentSubsectionModel subsectionModel = sender as TridentSubsectionModel;
            if (this.composerControl.UIElements.ContainsKey(subsectionModel.UniqueId))
            {
                ISubsectionControl currentSubsection = this.composerControl.UIElements[subsectionModel.UniqueId] as ISubsectionControl;
                if (currentSubsection != null)
                {
                    SubsectionExpandedCtrl expandedCurrentCtrl = currentSubsection as SubsectionExpandedCtrl;
                    SubsectionCollapsedCtrl collapsedCtrl = currentSubsection as SubsectionCollapsedCtrl;
                    if ((subsectionModel.IsCollapsed && collapsedCtrl != null)
                        || (!subsectionModel.IsCollapsed && expandedCurrentCtrl != null))
                    {
                        return;
                    }

                    if (this.composerControl.UIElements.ContainsKey(subsectionModel.ParentModel.UniqueId))
                    {
                        ICompositeUIElement parentElem = this.composerControl.UIElements[subsectionModel.ParentModel.UniqueId] as ICompositeUIElement;
                        if (parentElem != null)
                        {
                            int prevIndex = parentElem.ChildElements.IndexOf(currentSubsection as ITridentUIElement);
                            if (prevIndex > -1)
                            {
                                if (subsectionModel.IsCollapsed)
                                {
                                    if (expandedCurrentCtrl != null && expandedCurrentCtrl.CollapsedCtrl != null && parentElem.ChildElements.Contains(expandedCurrentCtrl))
                                    {
                                        if (parentElem.RemoveChildElement(expandedCurrentCtrl as ITridentUIElement))
                                        {
                                            parentElem.InsertChildElement(expandedCurrentCtrl.CollapsedCtrl as ITridentUIElement, prevIndex);
                                            this.uIElements[subsectionModel.UniqueId] = expandedCurrentCtrl.CollapsedCtrl as ITridentUIElement;
                                        }
                                    }
                                }
                                else
                                {
                                    if (collapsedCtrl != null && collapsedCtrl.ExpandedCtrl != null && parentElem.ChildElements.Contains(collapsedCtrl))
                                    {
                                        if (parentElem.RemoveChildElement(collapsedCtrl as ITridentUIElement))
                                        {
                                            parentElem.InsertChildElement(collapsedCtrl.ExpandedCtrl as ITridentUIElement, prevIndex);
                                            this.uIElements[subsectionModel.UniqueId] = collapsedCtrl.ExpandedCtrl as ITridentUIElement;
                                        }
                                    }
                                }

                                this.IsWFCommitted = false;
                                this.connectionVisitor.DeleteTridentUIElement();
                            }
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Fired on swap of the subsection state.
        /// </summary>
        /// <param name="sender">
        /// Subsection control.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnSwapSubsectionState(object sender, EventArgs e)
        {
            this.SwapSubsectionState(sender);
        }

        private void OnTridentElemSelect(object sender, EventArgs e)
        {
            
        }

        private void OnTridentActivityElemShowProperties(object sender, EventArgs e)
        {
            this.ShowProperties();
        }

        private void OnTridentActivityToggleParamBindings(object sender, ParameterBindingEventArgs e)
        {
            foreach (ITridentUIElement uiElem in this.selectedElements)
            {
                BaseModel parentActModel = uiElem.Model;

                // Change the parameter binding visibilty of the activity Model.
                this.ChangeParameterBindingVisibilty(parentActModel, e.ParameterBindingVisibility);

                // Refresh the binding parameters.
                this.parameterBindingVisitor.RefreshVisibility(parentActModel);
            }
        }

        private void OnRemoveSubsection(object sender, RemoveSubsectionEventArgs e)
        {
            TridentSubsectionModel subsectionModelToRemove = e.SubsectionModelToRemove;
            if (subsectionModelToRemove != null)
            {
                BaseCompositeModel parentModel = subsectionModelToRemove.ParentModel;
                if (parentModel != null && parentModel.Children.Contains(subsectionModelToRemove))
                {
                    int indexOfSubsection = parentModel.Children.IndexOf(subsectionModelToRemove);
                    int subsectionChildrenCount = subsectionModelToRemove.Children.Count;

                    if (indexOfSubsection > -1)
                    {
                        for (int index = 0; index < subsectionModelToRemove.Children.Count; index++)
                        {
                            BaseModel model = subsectionModelToRemove.Children[index];
                            model.ParentModel = parentModel;
                            parentModel.Children.Insert(index + indexOfSubsection, model);
                        }
                    }

                    ICompositeUIElement parentElem = null;
                    ITridentUIElement subsectionElem = null;
                    subsectionModelToRemove.Children.Clear();
                    if (this.uIElements.ContainsKey(subsectionModelToRemove.UniqueId))
                    {
                        subsectionElem = this.uIElements[subsectionModelToRemove.UniqueId];
                        if (parentModel.Children.Remove(subsectionModelToRemove) && this.uIElements.ContainsKey(parentModel.UniqueId))
                        {
                            parentElem = this.uIElements[parentModel.UniqueId] as ICompositeUIElement;
                            if (parentElem != null && subsectionElem != null && parentElem.ChildElements.Contains(subsectionElem))
                            {
                                ICompositeUIElement compositeSubsectionElem = null;
                                SubsectionCollapsedCtrl collapsedSubsectionElem = subsectionElem as SubsectionCollapsedCtrl;
                                if (subsectionElem is SubsectionExpandedCtrl)
                                {
                                    compositeSubsectionElem = subsectionElem as ICompositeUIElement;
                                }
                                else if (collapsedSubsectionElem != null)
                                {
                                    compositeSubsectionElem = collapsedSubsectionElem.ExpandedCtrl;
                                }

                                if (compositeSubsectionElem != null)
                                {
                                    Collection<ITridentUIElement> subsectionChildElements = compositeSubsectionElem.ChildElements;
                                    compositeSubsectionElem.MainContentHolder.Children.Clear();
                                    parentElem.RemoveChildElement(subsectionElem);
                                    if (subsectionChildElements.Count > 0)
                                    {
                                        for (int index = indexOfSubsection; index < (indexOfSubsection + subsectionChildrenCount); index++)
                                        {
                                            ITridentUIElement childElem = subsectionChildElements[index - indexOfSubsection];
                                            if (childElem != null)
                                            {
                                                parentElem.InsertChildElement(childElem, index);
                                            }
                                        }
                                    }
                                }

                                // Set the workflow has been updated.
                                this.IsWFCommitted = false;
                                this.connectionVisitor.DeleteTridentUIElement();
                            }
                        }

                        if (this.selectedElements.Contains(subsectionElem))
                        {
                            this.selectedElements.Remove(subsectionElem);
                        }
                    }

                    this.OnPropPaneClose(this, new EventArgs());
                }
            }
        }

        private void OnTridentElementKeyDown(object sender, KeyEventArgs e)
        {
            if (Key.Delete == e.Key)
            {
                if (this.selectedElements.OnlyActivitiesSupportingDelete)
                {
                    this.OnTridentElemDelete(null, null);
                }
                e.Handled = true;
            }
        }

        private void OnInsertIntoSubsection(object sender, EventArgs e)
        {
            if (this.selectedElements.Count > 0)
            {
                ITridentUIElement firstElem = this.selectedElements[0];
                this.GetNewSubsectionName(string.Empty, string.Empty);
                
                // check if subsection with same already exists
                while (this.DoesSubsectionExists(this.CurrentWorkflowModel.ModelsHashtable.Values.OfType<TridentSubsectionModel>()))
                {
                    TridentMessageBox.ShowTridentInformationMessageBox(TridentResourceManager.GetString("DuplicateSubsectionName"));
                    
                    // accept the name and description once again
                    this.GetNewSubsectionName(this.subsectionName, this.descSubsection);
                }
                if (string.IsNullOrEmpty(this.subsectionName))
                {
                    return;
                }

                BaseCompositeModel parentActModel = firstElem.Model.ParentModel;
                if (parentActModel != null)
                {
                    TridentSubsectionModel subsectionModel = new TridentSubsectionModel(
                        SubsectionMetadata.Data,
                        parentActModel,
                        this.subsectionName,
                        this.descSubsection,
                        ActivityUtilities.UniqueCounter.ToString(CultureInfo.InvariantCulture));

                    subsectionModel.SwapSubsectionState += new EventHandler(this.OnSwapSubsectionState);
                    parentActModel.Children.Insert(firstElem.Model.IndexOfModel, subsectionModel);

                    ISubsectionControl subsectionCtrl = this.uiGenerationVisitor.GenerateUIRepresentation(subsectionModel, this.dataTypes, this.uIElements, this) as ISubsectionControl;
                    if (subsectionCtrl != null)
                    {
                        subsectionCtrl.RemoveSubsection += new EventHandler<RemoveSubsectionEventArgs>(this.OnRemoveSubsection);
                        ITridentUIElement element = null;
                        if (this.uIElements.TryGetValue(subsectionModel.ParentModel.UniqueId, out element))
                        {
                            ICompositeUIElement compositeElem = element as ICompositeUIElement;
                            if (compositeElem != null)
                            {
                                ITridentUIElement subsectionTridentElem = subsectionCtrl as ITridentUIElement;
                                compositeElem.InsertChildElement(subsectionTridentElem, subsectionModel.IndexOfModel);

                                ICompositeUIElement subsectionCompositeElem = subsectionCtrl as ICompositeUIElement;
                                if (subsectionCompositeElem != null)
                                {
                                    foreach (ITridentUIElement uiElem in this.selectedElements)
                                    {
                                        if (parentActModel.Children.Contains(uiElem.Model) && parentActModel.Children.Remove(uiElem.Model)
                                            && compositeElem.ChildElements.Contains(uiElem) && compositeElem.RemoveChildElement(uiElem))
                                        {
                                            subsectionModel.Children.Add(uiElem.Model);
                                            uiElem.Model.ParentModel = subsectionModel;
                                            subsectionCompositeElem.AddChildElement(uiElem);
                                        }
                                    }

                                    this.connectionVisitor.DeleteTridentUIElement();
                                    this.parameterBindingVisitor.RefreshBindings();
                                    this.IsWFCommitted = false;
                                    this.OnPropPaneClose(this, new EventArgs());
                                }
                            }
                        }
                    }
                }
            }
        }

        private void OnUpdateClick(object sender, ModelEventArgs args)
        {
            if (args != null && args.Model != null && !args.Model.Id.Equals(args.Model.LatestEntityId))
            {
                ModelFactory modelFactory = new ModelFactory(null, null);
                BaseModel updatedModel = modelFactory.FetchModelByERActivityId(
                    args.Model.LatestEntityId, 
                    this.registryConnection, 
                    args.Model.ParentModel,
                    ActivityUtilities.UniqueCounter.ToString(CultureInfo.InvariantCulture));

                if (updatedModel != null)
                {
                    // In case of IfElse model, the child models need to be updated.
                    if (args.Model.IsIfElseActivityModel)
                    {
                        // Access the IfCondition model and the IfTrue and IfFalse branches, and implictly call update on those.
                        BaseCompositeModel ifElseModel = args.Model as BaseCompositeModel;
                        if (ifElseModel != null)
                        {
                            for (int ifElseChildCount = 0; ifElseChildCount < ifElseModel.Children.Count; ifElseChildCount++)
                            {
                                BaseModel childModel = ifElseModel.Children[ifElseChildCount];

                                // Update the IfCondition block.
                                if (childModel.ActivityClass.Equals(UIDesignerCodeConstants.ACTIVITYCLASSIFCONDITION, StringComparison.OrdinalIgnoreCase))
                                {
                                    this.OnUpdateClick(this, new ModelEventArgs(childModel));
                                }
                                // Update the IfTrue and IfFalse blocks.
                                else if (childModel.ActivityClass.Equals(UIDesignerCodeConstants.ACTIVITYCLASSPARALLEL))
                                {
                                    BaseCompositeModel branchModel = childModel as BaseCompositeModel;
                                    if (branchModel != null)
                                    {
                                        for (int branchModelChild = 0; branchModelChild < branchModel.Children.Count; branchModelChild++)
                                        {
                                            CompositeActivityModel branchChildModel = branchModel.Children[branchModelChild] as CompositeActivityModel;
                                            for (int branchChildModelCount = 0; branchChildModelCount < branchChildModel.Children.Count; branchChildModelCount++)
                                            {
                                                this.OnUpdateClick(this, new ModelEventArgs(branchChildModel.Children[branchChildModelCount]));
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    
                    if (args.Model.IsCompositeActivityModel 
                        && updatedModel.IsCompositeActivityModel 
                        || args.Model.IsCompositeBlackBoxModel 
                        && updatedModel.IsCompositeBlackBoxModel)
                    {
                        BaseCompositeModel updatedCompositeModel = updatedModel as BaseCompositeModel;
                        foreach (BaseModel child in (args.Model as BaseCompositeModel).Children)
                        {
                            updatedCompositeModel.Children.Add(child);
                            child.ParentModel = updatedCompositeModel;
                        }
                    }

                    this.UpdateInputOutputValues(args.Model, updatedModel);
                    BaseCompositeModel parentModel = updatedModel.ParentModel;
                    if (null != parentModel && parentModel.Children.Contains(args.Model))
                    {
                        int indexOfElem = parentModel.Children.IndexOf(args.Model);
                        if (indexOfElem > -1 && parentModel.Children.Remove(args.Model))
                        {
                            parentModel.Children.Insert(indexOfElem, updatedModel);
                            this.CurrentComposerCtrl.LoadWorkflow(this.CurrentWorkflowModel, true);
                            this.IsWFCommitted = false;
                        }
                    }
                }
            }
        }

        private void OnTridentUiElemProvenanceMenuClick(object sender, ProvenanceModeEventArgs e)
        {
            this.ProvenanceMenuClick.Fire(sender, e);
        }

        private void UpdateInputOutputValues(BaseModel oldModel, BaseModel newModel)
        {
            ComposerRenderer.UpdateAssignedValues(oldModel, newModel);
            this.UpdateOutboundBindings(oldModel, newModel);
            ComposerRenderer.UpdateInboundBindings(oldModel, newModel);
        }

        private static void UpdateAssignedValues(BaseModel oldModel, BaseModel newModel)
        {
            IEnumerable<ParameterDescriptionModel> assignedParams = oldModel.InputParameters.Where(inputParam => !inputParam.IsDatabound);
            foreach (ParameterDescriptionModel oldParam in assignedParams)
            {
                foreach (ParameterDescriptionModel newParam in newModel.InputParameters)
                {
                    if (!newParam.IsDatabound 
                        && oldParam.PropertyName.Equals(newParam.PropertyName, StringComparison.OrdinalIgnoreCase))
                    {
                        newParam.Value = oldParam.Value;
                        break;
                    }
                }
            }
        }

        private static void UpdateInboundBindings(BaseModel oldModel, BaseModel newModel)
        {
            IEnumerable<ParameterDescriptionModel> boundParams = oldModel.InputParameters.Where(inputParameter => inputParameter.IsDatabound);
            if (boundParams.Count() > 0)
            {
                newModel.InputParameters.ForEach(
                    newParamModel => boundParams.ForEach(
                        oldParamModel => ComposerRenderer.UpdateInboundBinding(oldParamModel, newParamModel)));
            }
        }

        private static void UpdateInboundBinding(ParameterDescriptionModel oldParamModel, ParameterDescriptionModel newParamModel)
        {
            if (oldParamModel != null
                && newParamModel != null
                && oldParamModel.PropertyName.Equals(newParamModel.PropertyName, StringComparison.OrdinalIgnoreCase))
            {
                DatabindModel oldBoundValue = oldParamModel.Value as DatabindModel;
                newParamModel.CreateBindings(oldBoundValue.SourceActivityName, oldBoundValue.SourcePropertyName);
            }
        }

        private void UpdateOutboundBindings(BaseModel oldModel, BaseModel newModel)
        {
            if (oldModel != null && oldModel.OutputParameters.Count > 0 && newModel != null && this.CurrentWorkflowModel != null)
            {
                Collection<BaseModel> modelsCollection = new Collection<BaseModel>();
                foreach (BaseModel model in this.CurrentWorkflowModel.ModelsHashtable.Values)
                {
                    modelsCollection.Add(model);
                }

                // For all input parameters in all models
                // Check if its data bound
                // If databound, check if the source activity name equals the previous name of the activity to be updated
                // and also, if the datatype of the parameters match
                // Foreach of those parameters, update the source activity name.
                modelsCollection.ForEach(model => model.InputParameters
                    .Where(inputParameter => inputParameter.IsDatabound)
                    .Where(inputParameter => ((inputParameter.Value as DatabindModel).SourceActivityName.Equals(oldModel.UniqueId, StringComparison.OrdinalIgnoreCase)))
                    .ForEach(inputParameter => (inputParameter.Value as DatabindModel).SourceActivityName = newModel.UniqueId));
            }
        }

        /// <summary>
        /// Update the data key legend.
        /// </summary>
        private void UpdateDataKey()
        {
            DataTypesLegendCtrl dataTypesLegendCtrlWindow = null;
            WindowCollection childWindows = this.mainWindow.OwnedWindows;
            foreach (Window child in childWindows)
            {
                if (child.Tag != null && child.Tag.ToString().Equals("DataTypesLegendCtrl" + this.composerControl.CurrentRenderMode.ToString()))
                {
                    dataTypesLegendCtrlWindow = child as DataTypesLegendCtrl;
                    break;
                }
            }

            if (dataTypesLegendCtrlWindow == null)
            {
                dataTypesLegendCtrlWindow = this.composerControl.InitializeDataTypeWindow();
            }

            dataTypesLegendCtrlWindow.ShownDataTypes.Clear();
            foreach (string dataType in this.inUseDataTypes.Keys)
            {
                if (this.inUseDataTypes[dataType] > 0)
                {
                    DataTypeModel typeModel = this.dataTypes[dataType];
                    dataTypesLegendCtrlWindow.ShownDataTypes.Add(typeModel);
                }
            }
        }      
        
        /// <summary>
        /// Add the param elements to the dictionary.
        /// </summary>
        /// <param name="element"></param>
        private void UpdateParamDictionary(TridentUIActivityElement element)
        {
            // Add the param elements into the dictionary.
            foreach (string key in element.InputParameterElements.Keys)
            {
                string globalKey = element.Model.UniqueId + "." + key;
                this.InputParameterElements[globalKey] = element.InputParameterElements[key];
            }

            // Add the param elements into the dictionary.
            foreach (string key in element.OutputParameterElements.Keys)
            {
                string globalKey = element.Model.UniqueId + "." + key;
                this.OutputParameterElements[globalKey] = element.OutputParameterElements[key];
            }
        }

        /// <summary>
        /// Returns the maximum counter value for the wf.
        /// </summary>
        /// <param name="activityModel">The activity model for which the max count needs to be found.</param>
        /// <param name="maxValue">the current maximum value.</param>
        /// <returns>max value.</returns>
        private int SetCounter(BaseModel activityModel, int maxValue)
        {
            int max = maxValue;

            // Get the activity model unique name.
            string activityModelName = activityModel.UniqueId;

            // Get the count of the activity. eg: delay_1, count = 1
            int activityCounter = ComposerRenderer.GetCount(activityModelName);

            // Check if the max value is lesser than the returned value.
            if (activityCounter > maxValue)
            {
                max = activityCounter;
            }

            // If composite then recurse through the children.
            if (activityModel.IsCompositeActivityModel || activityModel.IsSubsectionModel || activityModel.IsCompositeBlackBoxModel)
            {
                BaseCompositeModel compositeModel = activityModel as BaseCompositeModel;
                foreach (BaseModel child in compositeModel.Children)
                {
                    max = SetCounter(child, max);
                }
            }

            // Return the maximum value.
            return max;
        }

        /// <summary>
        /// Get the count from the name.
        /// </summary>
        /// <param name="name">name</param>
        /// <returns>count</returns>
        private static int GetCount(string name)
        {
            char[] saperator = { '_' };

            // Split the name by _
            string[] nameSplit = name.Split(saperator);
            try
            {
                if (nameSplit.Length < 2)
                {
                    // Return -1 to signify failure.
                    return -1;
                }
                else
                {
                    // Parse the integer value.
                    return int.Parse(nameSplit[nameSplit.Length - 1], CultureInfo.InvariantCulture);
                }
            }
            catch (FormatException)
            {
                return -1;
            }
        }

        /// <summary>
        /// This function is used to recursively chnage the state of the activity.
        /// </summary>
        /// <param name="actModel">Activity Model.</param>
        /// <param name="changeState">Change State.</param>
        private void ChangeParameterBindingVisibilty(BaseModel actModel, Visibility changeState)
        {
            actModel.CurrentParameterBindingVisibility = changeState;

            BaseCompositeModel baseComposite = actModel as BaseCompositeModel;
            if (baseComposite != null)
            {
                foreach (BaseModel childActModel in baseComposite.Children)
                {
                    this.ChangeParameterBindingVisibilty(childActModel, changeState);
                }
            }
        }

        /// <summary>
        /// Updates the property pane.
        /// </summary>
        /// <param name="actModel">
        /// Activity model.
        /// </param>
        /// <param name="wfModel">
        /// Workflow model.
        /// </param>
        private void UpdatePropPane(BaseModel actModel, TridentWorkflowModel wfModel, bool showWorkflowParameters)
        {
            if (actModel != null)
            {
                Grid grdPropPaneHolder = this.composerControl.grdCentralPane;
                if (grdPropPaneHolder != null)
                {
                    PropertiesPane propPane = null;
                    if (grdPropPaneHolder.Children.Count > 2 && grdPropPaneHolder.Children[2] is PropertiesPane)
                    {
                        propPane = grdPropPaneHolder.Children[2] as PropertiesPane;
                    }

                    if (null == propPane)
                    {
                        if (wfModel != null)
                        {
                            propPane = new PropertiesPane(this.registryConnection, wfModel, showWorkflowParameters);
                        }
                        else
                        {
                            propPane = new PropertiesPane(this.registryConnection, actModel);
                        }

                        propPane.ClosePropPane += new EventHandler(this.OnPropPaneClose);
                        propPane.Margin = new Thickness(8, 0, 0, 0);
                        propPane.Name = "propPane";
                        grdPropPaneHolder.Children.Add(propPane);
                        Grid.SetColumn(propPane, 1);
                        ComposerRenderer.ShowPropPaneHolder(grdPropPaneHolder);
                    }
                    else
                    {
                        if (wfModel != null)
                        {
                            propPane.WFModel = wfModel;

                            if (showWorkflowParameters)
                            {
                                propPane.ShowWorkflowParametersTab();
                            }
                        }
                        else
                        {
                            propPane.ActivityModel = actModel;
                        }
                    }
                }
            }
        }

        /// <summary>
        /// Shows the property pane.
        /// </summary>
        /// <param name="grdHolder">
        /// The property pane holder.
        /// </param>
        private static void ShowPropPaneHolder(Grid grdHolder)
        {
            ColumnDefinition colDefn = grdHolder.ColumnDefinitions[1];
            colDefn.Width = new GridLength(300);
            colDefn.MinWidth = 230;
            colDefn.MaxWidth = 500;
        }

        /// <summary>
        /// Hides the property pane.
        /// </summary>
        /// <param name="grdHolder">
        /// The property pane holder.
        /// </param>
        private static void HidePropPaneHolder(Grid grdHolder)
        {
            ColumnDefinition colDefn = grdHolder.ColumnDefinitions[1];
            colDefn.Width = new GridLength(0);
            colDefn.MinWidth = 0;
            colDefn.MaxWidth = 0;
        }

        /// <summary>
        /// Fired on close of the property pane.
        /// </summary>
        /// <param name="sender">
        /// Property pane.
        /// </param>
        /// <param name="e">
        /// EventArgs.
        /// </param>
        private void OnPropPaneClose(object sender, EventArgs e)
        {
            Grid grdPropPaneHolder = this.composerControl.grdCentralPane;
            if (grdPropPaneHolder != null)
            {
                if (grdPropPaneHolder.Children.Count > 2 && grdPropPaneHolder.Children[2] is PropertiesPane)
                {
                    grdPropPaneHolder.Children.RemoveAt(2);
                }

                ComposerRenderer.HidePropPaneHolder(grdPropPaneHolder);
            }
        }

        /// <summary>
        /// Create a new subsection.
        /// </summary>
        /// <param name="sender">
        /// WorkflowActivityConnectionElement.
        /// </param>
        /// <param name="e">
        /// SubsectionCreationEventArgs, specifies the index of subsection and the parent activity model.
        /// </param>
        internal void OnCreateNewSubsection(object sender, SubsectionCreationEventArgs e)
        {
            if (SubsectionMetadata.Data == null)
            {
                TridentMessageBox.ShowTridentInformationMessageBox(Application.Current.MainWindow,
                            TridentResourceManager.GetString("SubsectionActivityDeleted"));
                return;
            }

            WorkflowActivityConnectionElement connElem = sender as WorkflowActivityConnectionElement;
            if (connElem != null)
            {
                bool containsEmbeddedWorkflow = false;
                if (e.WorkflowMetadata != null)
                {
                    containsEmbeddedWorkflow = true;
                }

                TridentWorkflowModel wfModel = null;
                List<TridentSubsectionModel> allSubsections = new List<TridentSubsectionModel>();
                if (!this.SubsectionNameCheckOnWfDrop(e.WorkflowMetadata, allSubsections, out wfModel))
                {
                    return;
                }
                
                if (containsEmbeddedWorkflow)
                {
                    this.GetNewSubsectionName(e.WorkflowMetadata.Name, e.WorkflowMetadata.Description);
                }
                else
                {
                    this.GetNewSubsectionName(string.Empty, string.Empty);
                }

                // check if subsection with same already exists
                while (this.DoesSubsectionExists(allSubsections))
                {
                    TridentMessageBox.ShowTridentInformationMessageBox(TridentResourceManager.GetString("DuplicateSubsectionName"));
                    
                    // accept the name and description once again
                    this.GetNewSubsectionName(this.subsectionName, this.descSubsection);
                }

                if (string.IsNullOrEmpty(this.subsectionName))
                {
                    return;
                }

                BaseCompositeModel parentActModel = e.ParentModel;
                if (parentActModel != null)
                {
                    TridentSubsectionModel subsectionModel = new TridentSubsectionModel(SubsectionMetadata.Data, e.ParentModel, this.subsectionName, this.descSubsection, ActivityUtilities.UniqueCounter.ToString(CultureInfo.InvariantCulture));
                    subsectionModel.SwapSubsectionState += new EventHandler(this.OnSwapSubsectionState);
                    if (containsEmbeddedWorkflow && wfModel != null)
                    {
                        this.AddWorkflowToSubsection(wfModel, subsectionModel);
                    }

                    parentActModel.Children.Insert(e.Index, subsectionModel);

                    ISubsectionControl subsectionCtrl = this.uiGenerationVisitor.GenerateUIRepresentation(subsectionModel, this.dataTypes, this.uIElements, this) as ISubsectionControl;
                    if (subsectionCtrl != null)
                    {
                        subsectionCtrl.RemoveSubsection += new EventHandler<RemoveSubsectionEventArgs>(this.OnRemoveSubsection);
                        ITridentUIElement element = null;
                        if (this.uIElements.TryGetValue(subsectionModel.ParentModel.UniqueId, out element))
                        {
                            ICompositeUIElement compositeElem = element as ICompositeUIElement;
                            if (compositeElem != null)
                            {
                                ITridentUIElement subsectionTridentElem = subsectionCtrl as ITridentUIElement;
                                compositeElem.InsertChildElement(subsectionTridentElem, e.Index);
                                connectionVisitor.InsertActivityConnection();
                            }
                        }
                    }
                }

                this.composerControl.IsWFCommitted = false;
            }
        }

        /// <summary>
        /// Checks whether a subsection with the same name already exists in the workflow model.
        /// </summary>
        /// <returns>
        /// true - if a subsection with the same name already exists
        /// false - a subsection with the same name does not exist
        /// </returns>
        private bool DoesSubsectionExists(IEnumerable<TridentSubsectionModel> allSubsections)
        {
            if (allSubsections == null)
            {
                throw new ArgumentNullException("allSubsections");
            }

            return allSubsections.Any(item => item.Label.Equals(this.subsectionName, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// Subsections name check on wf drop.
        /// </summary>
        /// <param name="wfMeta">The wf meta.</param>
        /// <param name="allSubsections">All subsections.</param>
        /// <param name="wfModel">The wf model.</param>
        /// <returns>If valid drop true, else false.</returns>
        private bool SubsectionNameCheckOnWfDrop(WorkflowMetadata wfMeta, List<TridentSubsectionModel> allSubsections, out TridentWorkflowModel wfModel)
        {
            wfModel = null;
            bool validDrop = true;
            // The list of subsections of the current workflow model.
            List<TridentSubsectionModel> currentSubsections = this.CurrentWorkflowModel.ModelsHashtable.Values.OfType<TridentSubsectionModel>().ToList();
            
            // Holds the list of subsections of the dropped workflow model.
            List<TridentSubsectionModel> containedSubsections = new List<TridentSubsectionModel>();
            if (wfMeta != null)
            {
                wfModel = this.wfLoader.GetWorkflowModel(wfMeta.Id, true);
                if (wfModel != null)
                {
                    containedSubsections.AddRange(wfModel.ModelsHashtable.Values.OfType<TridentSubsectionModel>().ToList());

                    // Check if there are subsections with the same label in the dropped workflow.
                    IEnumerable<TridentSubsectionModel> modelsWithSameLabels = containedSubsections.Intersect(currentSubsections, new SubsectionModelLabelComparer());
                    if (modelsWithSameLabels.Count() > 0)
                    {
                        StringBuilder clashingNames = new StringBuilder(ManagementStudioResourceManager.GetString("NonUniqueSubsectionNamesOnDrop"));
                        modelsWithSameLabels.ForEach(item => clashingNames.Append(item.Label + ", "));
                        TridentMessageBox.ShowTridentErrorMessageBox(clashingNames.ToString(0, clashingNames.Length - 2));
                        validDrop = false;
                    }
                }
            }

            if (validDrop)
            {
                allSubsections.AddRange(currentSubsections);
                allSubsections.AddRange(containedSubsections);
            }

            return validDrop;
        }

        /// <summary>
        /// Handles drop of a workflow into a workflow.
        /// </summary>
        /// <param name="wfMeta">
        /// The metadata of the dropped workflow.
        /// </param>
        /// <param name="subsectionToAddTo">
        /// The subsection into which this will be added.
        /// </param>
        private void AddWorkflowToSubsection(TridentWorkflowModel wfModelToAdd, TridentSubsectionModel subsectionToAddTo)
        {
            if (wfModelToAdd != null && subsectionToAddTo != null)
            {
                BaseCompositeModel rootActModel = wfModelToAdd.Root;
                if (rootActModel != null)
                {
                    Hashtable changedUniqueIds = new Hashtable();
                    this.UpdateActUniqIdOnWfDrop(rootActModel, changedUniqueIds);
                    if (changedUniqueIds != null && changedUniqueIds.Count > 0)
                    {
                        foreach (string key in changedUniqueIds.Keys)
                        {
                            this.UpdateDataBindMeta(rootActModel, (string)key, (string)changedUniqueIds[key]);
                        }
                    }

                    // If blackbox workflow then set the reference workflow activity in the current model
                    // update the names which have been reassigned.
                    if (wfModelToAdd.IsBlackBox)
                    {
                        WorkflowComposer.UpdateActivityNames(wfModelToAdd.BlackBoxActivity, changedUniqueIds);
                        if (this.CurrentWorkflowModel.BlackBoxActivity == null)
                        {
                            this.CurrentWorkflowModel.BlackBoxActivity = wfModelToAdd.BlackBoxActivity;
                        }
                        else
                        {
                            // If already a blackbox workflow in the current workflow then append the children to the same.
                            CompositeActivity compositeActivity = this.CurrentWorkflowModel.BlackBoxActivity as CompositeActivity;
                            CompositeActivity addedComposite = wfModelToAdd.BlackBoxActivity as CompositeActivity;
                            compositeActivity.Activities.AddRange(addedComposite.Activities);
                        }
                    }

                    foreach (BaseModel model in rootActModel.Children)
                    {
                        subsectionToAddTo.Children.Add(model);
                        model.ParentModel = subsectionToAddTo;

                        // Update the Visibilty of the parameter binding.
                        this.ChangeParameterBindingVisibilty(model, subsectionToAddTo.ParentModel.CurrentParameterBindingVisibility);
                    }
                }
                wfModelToAdd.SwapSubsectionState += this.OnSwapSubsectionState;
            }
        }

        /// <summary>
        /// Update the models' unique ids upon drop of workflow into a subsection.
        /// </summary>
        /// <param name="parentModel">
        /// The parent model.
        /// </param>
        private void UpdateActUniqIdOnWfDrop(BaseModel model, Hashtable changedUniqueIds)
        {
            if (null == changedUniqueIds)
            {
                changedUniqueIds = new Hashtable();
            }

            if (model != null)
            {
                string prevId = model.UniqueId;
                model.UniqueId = model.UniqueId + "_" + ComposerRenderer.UniqueCounter.ToString(CultureInfo.InvariantCulture);
                changedUniqueIds[prevId] = model.UniqueId;
            }

            BaseCompositeModel compositeModel = model as BaseCompositeModel;
            if (compositeModel != null)
            {
                foreach (BaseModel childModel in compositeModel.Children)
                {
                    this.UpdateActUniqIdOnWfDrop(childModel, changedUniqueIds);
                }
            }
        }

        /// <summary>
        /// Run through the activity models of the workflow, update the source activity ids if the unique id is updated.
        /// </summary>
        /// <param name="parentModel">
        /// The changed activity model.
        /// </param>
        /// <param name="oldActivityId">
        /// The old id, which will be used for searching.
        /// </param>
        private void UpdateDataBindMeta(BaseModel model, string oldActivityId, string newActivityId)
        {
            if (model != null && model.InputParameters != null && model.InputParameters.Count > 0)
            {
                foreach (ParameterDescriptionModel paramDescModel in model.InputParameters)
                {
                    if (paramDescModel.IsDatabound && paramDescModel.Value != null)
                    {
                        DatabindModel dataBindModelToUpdate = paramDescModel.Value as DatabindModel;
                        if (dataBindModelToUpdate != null && dataBindModelToUpdate.SourceActivityName.Equals(oldActivityId, StringComparison.OrdinalIgnoreCase))
                        {
                            dataBindModelToUpdate.SourceActivityName = newActivityId;
                        }
                    }
                }
            }

            BaseCompositeModel compositeModel = model as BaseCompositeModel;
            if (compositeModel != null)
            {
                foreach (BaseModel childModel in compositeModel.Children)
                {
                    this.UpdateDataBindMeta(childModel, oldActivityId, newActivityId);
                }
            }
        }

        /// <summary>
        /// Popup a dialog to get the workflow name.
        /// </summary>
        private void GetNewSubsectionName(string defaultName, string defaultDescription)
        {
            WorkflowMetaPopup enterMeta = new WorkflowMetaPopup();
            if (!string.IsNullOrEmpty(defaultName))
            {
                enterMeta.WorkflowName = defaultName;
            }

            if (!string.IsNullOrEmpty(defaultDescription))
            {
                enterMeta.WorkflowDescription = defaultDescription;
            }

            this.subsectionName = string.Empty;
            this.descSubsection = string.Empty;
            enterMeta.MainHeader = "Subsection";
            enterMeta.InfoEntered += new EventHandler<InfoEnteredEventArgs>(this.OnNameEntered);

            enterNamePopUp = new Window();
            enterMeta.HeaderDrag += (sender, e) => { enterNamePopUp.DragMove(); };
            enterNamePopUp.Content = enterMeta;
            enterNamePopUp.WindowStartupLocation = WindowStartupLocation.CenterOwner;
            enterNamePopUp.WindowStyle = WindowStyle.None;
            enterNamePopUp.ShowInTaskbar = false;
            enterNamePopUp.SizeToContent = SizeToContent.WidthAndHeight;
            enterNamePopUp.Owner = Application.Current.MainWindow;
            enterNamePopUp.BorderBrush = new SolidColorBrush(Colors.Transparent);
            enterNamePopUp.BorderThickness = new Thickness(0, 0, 0, 0);
            enterNamePopUp.ResizeMode = ResizeMode.NoResize;
            enterNamePopUp.ShowDialog();
        }

        /// <summary>
        /// Event handler when the ok is pressed on the dialog.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void OnNameEntered(object sender, InfoEnteredEventArgs e)
        {
            if (this.enterNamePopUp != null)
            {
                this.enterNamePopUp.Close();
            }

            if (!e.IsCancel)
            {
                this.subsectionName = e.InfoEntered.Trim();
                this.descSubsection = e.InfoDescriptionEntered.Trim();
            }
        }
        
        private void OnSelectedItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (this.SelectedActivitiesChanged != null)
            {
                this.SelectedActivitiesChanged.Invoke(this, new EventArgs());
            }
        }
                
        #endregion Private Methods 
    }

    /// <summary>
    /// Helper class for comparing 2 models.
    /// </summary>
    public class SubsectionModelLabelComparer : IEqualityComparer<TridentSubsectionModel>
    {
        #region IEqualityComparer<TridentSubsectionModel> Members

        /// <summary>
        /// Determines whether the specified objects are equal.
        /// </summary>
        /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
        /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
        /// <returns>
        /// true if the specified objects are equal; otherwise, false.
        /// </returns>
        public bool Equals(TridentSubsectionModel x, TridentSubsectionModel y)
        {
            return (x.Label.Equals(y.Label, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// Returns a hash code for the specified object.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
        /// <returns>A hash code for the specified object.</returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.
        /// </exception>
        public int GetHashCode(TridentSubsectionModel obj)
        {
            return obj.Label.GetHashCode();
        }

        #endregion
    }
}
